/**
******************************************************************************************
* @file HumidityController.c
* @brief Management of the criticality of the humidity.
* @date 29 mars 2015
* @author Benjamin Lancinot
*****************************************************************************************/
/* COPYRIGHT ****************************************************************************
*****************************************************************************************
* Copyright (c) 2015, Audrey LOISEAU and Benjamin LANCINOT.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
*    list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
********************************************************************************************/

#include "HumidityController.h"

/*******************************************************************************************
 * PROTOTYPES
 ********************************************************************************************/

void HumidityController_destroyUtilities(HumidityController*);

void HumidityController_destroy(HumidityController**);

void HumidityController_defineHumidityCriticality(HumidityController*, float);

int HumidityController_registerObserver(HumidityController*, Observer*);

int HumidityController_unregisterObserver(HumidityController*, Observer*);

/*******************************************************************************************
* FUNCTIONS
********************************************************************************************/

/**
 * @brief Constructor
 * @return Pointer to a new HumidityController
 **/
HumidityController* HumidityController_create(){
	HumidityController* This = (HumidityController *) malloc(sizeof(*This));

        //Init functions
        This->destroy = HumidityController_destroy;
        This->defineCriticality = HumidityController_defineHumidityCriticality;
	This->subject = subjectNew(This, 5);
	This->registerObserver = HumidityController_registerObserver;
	This->unregisterObserver = HumidityController_unregisterObserver;

        //Init variable
        This->criticality = NO_HUMIDITY;

	return This;
}

/**
 * @brief Destroy all of the components of HumidityController
 * @param This Pointer to the wanted HumidityController
 **/
void HumidityController_destroyUtilities(HumidityController* This)
{
	This->subject->destroy(This->subject);
}

/**
 * @brief Destructor
 * @param This Double pointer to the wanted HumidityController
 **/
void HumidityController_destroy(HumidityController** This)
{
HumidityController_destroyUtilities(* This);
	if (NULL != *This) {
		free(*This);
		*This = NULL;
	}
}


/**
 * @brief State machine use by the callback function of humidityTester for notify observers when the criticality of the humidity changed
 * @param This Pointer to the wanted MercureController
 * @param humidity Value of the humidity given by the bricklet
 **/
void HumidityController_defineHumidityCriticality(HumidityController* This, float humidity) {
		switch(This->criticality) {
	case NO_HUMIDITY:
	        if( humidity > 0 && humidity < H_LC ){
			This->criticality= CRITIC_COLD_HUMIDITY;

		}
		else if( humidity > H_HC){
			This->criticality= CRITIC_HOT_HUMIDITY;

		}
		else if( humidity >= H_LC && humidity < H_LM){
			This->criticality= MODERATE_COLD_HUMIDITY;

		}
                else if( humidity > H_HM && humidity <= H_HC ){
			This->criticality= MODERATE_HOT_HUMIDITY;

		}
                else{
			This->criticality= NORMAL_HUMIDITY;

                }
                This->subject->notifyObservers(This->subject);
		break;
	case NORMAL_HUMIDITY:
		if( humidity>= H_LC && humidity <H_LML  ){
			This->criticality= MODERATE_COLD_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity >H_HC ){
			This->criticality= CRITIC_HOT_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity < H_LC){
			This->criticality= CRITIC_COLD_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else if( humidity <= H_HC  && humidity> H_HMH  ){
			This->criticality= MODERATE_HOT_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else{
			This->criticality = NORMAL_HUMIDITY;

                }
		break;
	case MODERATE_COLD_HUMIDITY:
		if( humidity <= H_HM && humidity >= H_LMH ){
			This->criticality= NORMAL_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity > H_HC ){
			This->criticality= CRITIC_HOT_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity < H_LCL ){
			This->criticality= CRITIC_COLD_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else if( humidity <= H_HC  && humidity > H_HM ){
			This->criticality= MODERATE_HOT_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else{
			This->criticality = MODERATE_COLD_HUMIDITY;

                }
		break;
	case MODERATE_HOT_HUMIDITY:
		if( humidity >= H_LM && humidity <= H_HML ){
			This->criticality= NORMAL_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity > H_HCH ){
			This->criticality= CRITIC_HOT_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity < H_LC ){
			This->criticality= CRITIC_COLD_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else if( humidity <H_LM && humidity >= H_LC ){
			This->criticality= MODERATE_COLD_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else{
			This->criticality = MODERATE_HOT_HUMIDITY;

                }
		break;
	case CRITIC_COLD_HUMIDITY:
                if( humidity >= H_LM && humidity <= H_HM ){
			This->criticality= NORMAL_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity > H_HC){
			This->criticality= CRITIC_HOT_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity >= H_LC && humidity < H_LM){
			This->criticality= MODERATE_COLD_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else if( humidity > H_HM && humidity <= H_HC ){
			This->criticality= MODERATE_HOT_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else{
			This->criticality = CRITIC_COLD_HUMIDITY;

                }
		break;
	case CRITIC_HOT_HUMIDITY:
		if( humidity >= H_LM && humidity <= H_HM ){
			This->criticality= NORMAL_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity < H_LC){
			This->criticality= CRITIC_COLD_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
		else if( humidity >= H_LC && humidity < H_LM){
			This->criticality= MODERATE_COLD_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else if( humidity > H_HM && humidity <= H_HC ){
			This->criticality= MODERATE_HOT_HUMIDITY;
                        This->subject->notifyObservers(This->subject);

		}
                else{
			This->criticality = CRITIC_HOT_HUMIDITY;

                }
		break;
	default:
		printf("ERROR : HumidityController MAE is out!\n  ");
		break;
	}

}

/**
 * @brief Proxy method for Register an observer for the HumidityController object.
 * @param This Pointer to the wanted HumidityController
 * @param This Pointer to the wanted observer
 * @return The result of the development of the registration (0 = GOOD and 1 = NOT GOOD)
 **/
int HumidityController_registerObserver(HumidityController* This, Observer* observer) {
	return This->subject->registerObserver(This->subject, observer);
}


/**
 * @brief Proxy method for Unregister observer for the HumidityController object.
 * @param This Pointer to the wanted HumidityController
 * @param This Pointer to the wanted observer
 * @return The result of the development of the unregistration (0 = GOOD and 1 = NOT GOOD)
 **/
int HumidityController_unregisterObserver(HumidityController* This, Observer* observer) {
	return This->subject->unregisterObserver(This->subject, observer);
}
